#region Using

using System;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Web.Hosting;
using System.Threading;
using System.Xml;
using System.Text;
using CoyoEden;
using CoyoEden.DataStore;
using System.Xml.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections.Specialized;
using CoyoEden.Web.Controls;
using System.Web.UI.HtmlControls;
using CoyoEden.Models;

#endregion

/// <summary>
/// Summary description for WidgetBase
/// </summary>
public abstract class WidgetBase : ViewBase
{
	#region member variables
	/// <summary>
	/// Prefix of a widget instance
	/// </summary>
	public static readonly string WIDGETID_PREFIX="widget";
	#endregion

	#region Properties

	private string _Title;
	/// <summary>
	/// Gets or sets the title of the widget. It is mandatory for all widgets to set the Title.
	/// </summary>
	/// <value>The title of the widget.</value>
	public string Title
	{
		get { return _Title; }
		set { _Title = value; }
	}

	private bool _ShowTitle;
	/// <summary>
	/// Gets or sets a value indicating whether [show title].
	/// </summary>
	/// <value><c>true</c> if [show title]; otherwise, <c>false</c>.</value>
	public bool ShowTitle
	{
		get { return _ShowTitle; }
		set { _ShowTitle = value; }
	}
	private string _CssFloat;
	/// <summary>
	/// Gets or sets the widget's css float value;
	/// </summary>
	/// <value><c>left</c> indicates having a class name ".left";otherwise <c>right</c>;default <c>""</c></value>
	public string CssFloat {
		get { return string.IsNullOrEmpty(_CssFloat)?"":_CssFloat; }
		set { _CssFloat = value; }
	}
	private bool _EndWithClearBoth;
	/// <summary>
	/// Whether this widget ends with <c><div class="clear"></div></c>
	/// </summary>
	public bool EndWithClearBoth {
		get { return _EndWithClearBoth; }
		set { _EndWithClearBoth = value; }
	}
	/// <summary>
	/// Gets the name. It must be exactly the same as the folder that contains the widget.
	/// </summary>
	public abstract string Name { get; }

	/// <summary>
	/// Gets wether or not the widget can be edited.
	/// <remarks>
	/// The only way a widget can be editable is by adding a edit.ascx file to the widget folder.
	/// </remarks>
	/// </summary>
	public abstract bool IsEditable { get; }

	private Guid _WidgetID;
	/// <summary>
	/// Gets the widget ID.
	/// </summary>
	/// <value>The widget ID.</value>
	public Guid WidgetID
	{
		get { return _WidgetID; }
		set { _WidgetID = value; }
	}
	private string _ZoneID;
	/// <summary>
	/// which zone this instance belongs to 
	/// </summary>
	public string ZoneID {
		get { return _ZoneID; }
		set { _ZoneID = value; }
	}

	#endregion

	/// <summary>
	/// This method works as a substitute for Page_Load. You should use this method for
	/// data binding etc. instead of Page_Load.
	/// </summary>
	public abstract void LoadWidget();

	#region Settings

  /// <summary>
  /// Get settings from data store
  /// </summary>
  /// <returns>Settings</returns>
  public StringDictionary GetSettings()
  {
		string cacheId = string.Format("{0}{1}",WIDGETID_PREFIX,WidgetID);
    if (Cache[cacheId] == null)
    {
      WidgetSettings ws = new WidgetSettings(WidgetID.ToString());
      Cache[cacheId] = (StringDictionary)ws.GetSettings();
    }
    return (StringDictionary)Cache[cacheId];
  }

	#endregion

	/// <summary>
	/// Sends server control content to a provided <see cref="T:System.Web.UI.HtmlTextWriter"></see> 
	/// object, which writes the content to be rendered on the client.
	/// </summary>
	/// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"></see> object that receives the server control content.</param>
	protected override void Render(HtmlTextWriter writer)
	{
		if (string.IsNullOrEmpty(Name))
			throw new NullReferenceException("Name must be set on a widget");

		StringBuilder sb = new StringBuilder();
		var cssfloat=(this.CssFloat=="none")?"":" "+this.CssFloat;
		var cssEndwithClearBoth = (this.EndWithClearBoth) ? " endwithclearboth" : "";
		sb.AppendFormat("<div class=\"widget {0}\" id=\"{1}{2}\">",this.Name.Replace(" ", string.Empty).ToLowerInvariant()+cssfloat+cssEndwithClearBoth,WIDGETID_PREFIX,WidgetID);

		if (Thread.CurrentPrincipal.IsInRole(PortalSettings.Instance.AdministratorRole))
		{
			sb.Append("<div class=\"widgettools\">");
			sb.AppendFormat("<a class=\"delete\" href=\"javascript:void(0)\" onclick=\"removeWidget('{0}','{1}','{2}');return false\" title=\"{3} widget\">X</a>", WidgetID, WIDGETID_PREFIX, _ZoneID, Resources.labels.delete);
			if (IsEditable)
				sb.AppendFormat("<a class=\"edit\" href=\"javascript:void(0)\" onclick=\"editWidget('{0}', '{1}','{2}');return false\" title=\"{3} widget\">{4}</a>",Name,WidgetID,_ZoneID,Resources.labels.edit,Resources.labels.edit);

			sb.Append("</div>");
		}

		if (ShowTitle)
			if(Thread.CurrentPrincipal.IsInRole(PortalSettings.Instance.AdministratorRole)){
				sb.AppendFormat("<h4 class=\"{0}\">{1}</h4>","cursormove",this.Title);
			}else{
				sb.AppendFormat("<h4>{0}</h4>",this.Title);
			}
		sb.Append("<div class=\"content\">");

		writer.Write(sb.ToString());
		base.Render(writer);
		writer.Write("</div>");
		writer.Write("</div>");
	}

	#region helper methods
	/// <summary>
	/// Add a widget's script
	/// </summary>
	/// <param name="jsPath"></param>
	/// <remarks>
	/// Not all widgets need js,so we don't let our base class invoke this method automatically.
	/// </remarks>
	protected void AddWidgetScript(string jsPath)
	{
		if (File.Exists(HttpContext.Current.Request.MapPath(jsPath)))
		{
			//if the js hasn't been loaded ,load the js
			bool hasbeenloaded = false;
			for (int i = 0; i < Page.Header.Controls.Count; i++)
			{
				HtmlControl control = Page.Header.Controls[i] as HtmlControl;
				//Get script control
				if (control != null && control.TagName.ToLower() == "script" && control.Attributes["type"] == "text/javascript" && control.Attributes["src"] != null)
				{
					if (control.Attributes["src"].IndexOf(string.Format("{0}.js", this.Name)) >= 0)
					{
						//js has been loaded.
						hasbeenloaded = true;
						break;
					}
					else
					{
						continue;
					}
				}
			}
			if (!hasbeenloaded)
			{
				Utils.AddJavaScriptInclude(jsPath, Page, true);
			}
		}
	}
	#endregion

}
